#include "litesafeinfoqueue.h"
#include "litemutex/litespinmutex.h"
#include "litemutex/litebalancemutex.h"
#include "litemutex/litelocker.h"
#include "liteutils.h"

LiteSafeInfoQueue::LiteSafeInfoQueue()
	: m_liteMutex(static_cast<LiteMutex*>(new LiteSpinMutex))
{
}

LiteSafeInfoQueue::~LiteSafeInfoQueue()
{
	if (!m_abort)
		destory();
}

void LiteSafeInfoQueue::push(const std::string& info)
{
	if (m_abort)
		return;

	{
		LiteLocker lock(m_liteMutex.get());
		m_infoQueue.push(info);
	}

	if (m_bWaiting.load(std::memory_order_seq_cst))
	{
		m_condition.notify_one();
	}
}

void LiteSafeInfoQueue::push(const std::string&& info)
{
	if (m_abort)
		return;

	{
		LiteLocker lock(m_liteMutex.get());
		m_infoQueue.push(info);
	}

	if (m_bWaiting.load(std::memory_order_seq_cst))
	{
		m_condition.notify_one();
	}
}

std::string LiteSafeInfoQueue::pop()
{
	if (m_abort)
		return "";

	if (isEmpty())
		wait();

	if (m_abort)
		return "";

	LiteLocker lock(m_liteMutex.get());
	if (m_infoQueue.empty())
		return "";

	std::string info = std::move(m_infoQueue.front());
	m_infoQueue.pop();

	return info;
}

bool LiteSafeInfoQueue::isEmpty() const
{
	LiteLocker lock(m_liteMutex.get());
	return m_infoQueue.size() == 0;
}

void LiteSafeInfoQueue::destory()
{
	m_abort.store(true, std::memory_order_seq_cst);
	if (m_bWaiting.load(std::memory_order_seq_cst))
	{
		m_condition.notify_one();
	}

	LiteLocker lock(m_liteMutex.get());
	m_infoQueue.swap(std::queue<std::string>());
}

void LiteSafeInfoQueue::wait()
{
	m_bWaiting.store(true);
	std::unique_lock<std::mutex> locker(m_waitMutex);
	while (!m_abort.load(std::memory_order_seq_cst) && isEmpty())
	{
		m_condition.wait(locker, [=]() {return m_abort.load(std::memory_order_seq_cst) || !isEmpty(); });
	}
	locker.unlock();
	m_bWaiting.store(false);
}